package com.phynos.wechat.wx;

import java.io.IOException;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;

/**
 * 用于接收 微信推送的servlet类（还包含微信认证）
 * @author lupc
 *
 */
public class WeChatEventNotify extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1742885258491055277L;

	private static final Logger LOG = Logger.getLogger(WeChatEventNotify.class);

	/**
	 * 微信认证
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String result = requestCheck(req);

		resp.setContentType("text/plain;charset=UTF-8");
		PrintWriter out = resp.getWriter();
		try {
			out.println(result);
			out.flush();
		} catch (Exception e) {
			System.out.println(e);
		}
	}

	/**
	 * 接收微信的消息推送
	 */
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String result = handleEventNotify(req);
		resp.setContentType("text/plain;charset=UTF-8");
		PrintWriter out = resp.getWriter();
		try {
			out.println(result);
			out.flush();
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}
	}

	public static final String WX_SERVER_PRE_TOKEN = "";
	
	/**
	 * 验证消息的确来自微信服务器
	 * @param request
	 * @return
	 */
	private String requestCheck(HttpServletRequest request){
		String result = null;		
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		//
		ArrayList<String> list=new ArrayList<>();
		list.add(nonce);
		list.add(timestamp);
		list.add(WX_SERVER_PRE_TOKEN);
		//将token、timestamp、nonce三个参数进行字典序排序  
		Collections.sort(list,new Comparator<String>() {  
			@Override  
			public int compare(String o1, String o2) {  
				return o1.compareTo(o2);  
			}  
		});
		//将三个参数字符串拼接成一个字符串进行sha1加密  
		String str = list.get(0)+list.get(1)+list.get(2);
		String r = SHA1(str);
		if(signature.equalsIgnoreCase(r.toString().toUpperCase())){
			result = echostr;
			LOG.info("微信服务器身份认证成功");
		} else {
			result = "认证失败";
			StringBuffer sb = new StringBuffer();
			sb.append("signature:" + signature);
			sb.append("，timestamp" + timestamp);
			sb.append("，nonce" + nonce);
			sb.append("，echostr" + echostr);
			LOG.warn("微信服务器身份认证失败，相关信息：" + sb.toString());
		}		
		return result;
	}

	private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };  
	private static String getFormattedText(byte[] bytes) {  
		int len = bytes.length;  
		StringBuilder buf = new StringBuilder(len * 2);  
		// 把密文转换成十六进制的字符串形式  
		for (int j = 0; j < len; j++) {  
			buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);  
			buf.append(HEX_DIGITS[bytes[j] & 0x0f]);  
		}  
		return buf.toString();  
	} 
	private String SHA1(String str) {  
		if (str == null) {  
			return null;  
		}  
		try {  
			MessageDigest messageDigest = MessageDigest.getInstance("SHA1");  
			messageDigest.update(str.getBytes());  
			return getFormattedText(messageDigest.digest());  
		} catch (Exception e) {  
			throw new RuntimeException(e);  
		}  
	}
	
	public static final XStream XS = new XStream(new StaxDriver());
	static {
		XS.processAnnotations(WeChatInputMessage.class);  
		// 将指定节点下的xml节点数据映射为对象  
		XS.alias("xml", WeChatInputMessage.class); 
	}	
	
	public String handleEventNotify(HttpServletRequest req){
		String result = WeChartMessage.MSG_SUCCESS;
		try {
			// 处理接收消息  
			ServletInputStream in = req.getInputStream();  
			// 将POST流转换为XStream对象  
			// 将流转换为字符串  
			StringBuilder xmlMsg = new StringBuilder();  
			byte[] b = new byte[4096];  
			for (int n; (n = in.read(b)) != -1;) {  
				xmlMsg.append(new String(b, 0, n, "UTF-8"));  
			}
			String xml = xmlMsg.toString();
			LOG.debug(xml);
			// 将xml内容转换为InputMessage对象  
			WeChatInputMessage inputMsg = (WeChatInputMessage) XS.fromXML(xml);  
			switch (inputMsg.getMsgType()) {
			case WeChartMessage.MSG_TYPE_TEXT:
				result = WeChartMessage.responseText(
						inputMsg.getFromUserName(),
						inputMsg.getToUserName(),
						"你发送的是：" + inputMsg.getContent()
						);
				break;
			case WeChartMessage.MSG_TYPE_EVENT://处理事件
				handleWeChatEvent(inputMsg);
				break;
			default:
				break;
			}
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}	
		LOG.debug(result);
		return result;
	}

	/**
	 * 处理事件
	 * @param inputMsg
	 * @return
	 */
	private String handleWeChatEvent(WeChatInputMessage inputMsg){
		String result = "";
		switch (inputMsg.getEvent()) {
		case WeChartMessage.MSG_EVENT_SUBSCRIBE://订阅

			break;
		case WeChartMessage.MSG_EVENT_UNSUBSCRIBE://取消订阅

			break;
		case WeChartMessage.MSG_EVENT_CLICK://菜单点击
			
			break;
		default:
			break;
		}		
		return result;
	}

}
